package nl.scalasim
package util

import nl.scalasim.Logging

/**
 * A store can store certain goods up to a specific amount. 
 *
 * @author Yigal Duppen
 * @since Nov 4, 2010
 */
class Storage(val capacity: Map[Goods, Int], val totalCapacity: Int) extends Logging {

  private var _stored = Map[Goods, Int]()
  def stored = _stored

  private var _remainingCapacity = capacity
  def remainingCapacity = _remainingCapacity

  private var totalRemainingCapacity = totalCapacity

  def store(goods: Goods, amount: Int): Int = {
    val availableAmount = _remainingCapacity(goods)
    val storedAmount = Math.min(availableAmount, amount)
    val currentlyStored = _stored.getOrElse(goods, 0)
    totalRemainingCapacity -= storedAmount

    _stored = _stored + (goods -> (currentlyStored + storedAmount))
    _remainingCapacity = _remainingCapacity + (goods -> (availableAmount - storedAmount))
    _remainingCapacity = _remainingCapacity mapValues { Math.min(_, totalRemainingCapacity)}

    log.info("Stored " + amount + " " + goods + " in " + _stored)

    storedAmount
  }

  def retrieve(goods: Goods, amount: Int): Int = {
    log.info("Retrieving " + amount + " " + goods + " from " + _stored)
    val storedAmount = _stored.getOrElse(goods, 0)
    val retrievedAmount = Math.min(storedAmount, amount)
    val remainingAmount = storedAmount - retrievedAmount
    totalRemainingCapacity += retrievedAmount

    _stored = remainingAmount match {
      case 0 => _stored - goods
      case n => _stored + (goods -> n)
    }
    _remainingCapacity = _remainingCapacity + (goods -> (_remainingCapacity(goods) + retrievedAmount))

    log.info("Actually retrieved: " + retrievedAmount)
    retrievedAmount
  }

  def view: Map[Goods, Amount] = {
    capacity map {
      keyValue => keyValue._1 -> Amount(stored.getOrElse(keyValue._1, 0), keyValue._2) 
    }
  }
}